package com.carl.zeus.config.websocket;

import com.alibaba.fastjson.JSON;
import com.carl.zeus.common.emnu.SendType;
import com.carl.zeus.common.emnu.UserStatus;
import com.carl.zeus.model.system.SysUser;
import com.carl.zeus.model.system.SysUserChat;

import javax.websocket.Session;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 */
public class IMManager {
	
    private final static List<SocketUser> list = new ArrayList<>();
    // SynchronizedMap类是定义在Collections中的一个静态内部类。它实现了Map接口，并对其中的每一个方法实现，通过synchronized 关键字进行了同步控制
    // Collections.synchronizedMap 返回的是一个线程安全的hashMap(原hashMap为线程不安全的，需要手动在线程中处理，synchronizedMap省去这一步骤)
    // 缓存用户
    private final static Map<String, SocketUser> cacheMap = Collections.synchronizedMap(new HashMap<>());
    // 在线用户
    private final static Map<String, SocketUser> sessionMap = Collections.synchronizedMap(new HashMap<>());
    // 提出用户
    private final static SysUserChat exitMessage = new SysUserChat(SendType.LEAVE.getType());
    // 在线用户名 列表
    private final static Set<String> usernames = new HashSet<>();

    /**
     * 用于将用户信息及session保存到缓存中
     * @param user 用户信息
     * @param session 
     */
    public synchronized static void addUser(SysUser user, Session session) {
        if (user != null && session != null && user.getUsername()!=null) {
            SocketUser exist = cacheMap.get(user.getUsername());
            if (exist != null) {
            	if(!session.getId().equals(exist.getSession().getId()) && exist.getSession() != null && exist.getSession().isOpen()){
            		try {
            			// 该用户重复登录，此处操作是发送消息通知客户端，你已经被挤掉线了
						exist.getSession().getBasicRemote().sendText(JSON.toJSONString(exitMessage));
					} catch (IOException e) {
						e.printStackTrace();
					}
            		sessionMap.remove(exist.getSession().getId());
            	}
            	// 设置新的session
                exist.setSession(session);
                exist.setUser(user);
                sessionMap.put(session.getId(), exist);
            } else {
                // 如果没有登录过，创建个SocketUser
                SocketUser socketUser = new SocketUser();
                socketUser.setUser(user);
                socketUser.setSession(session);
                socketUser.getUser().setState(UserStatus.Online);
                list.add(socketUser);
                cacheMap.put(user.getUsername(), socketUser);
                sessionMap.put(session.getId(), socketUser);
            }
            // 加在 用户名列表中
            usernames.add(user.getUsername());
        }
    }
    
    public synchronized static void removeUser(SocketUser exist, Session session) {
            if (exist != null) {
            	if(session.getId().equals(exist.getSession().getId()) && exist.getSession() != null){
            		sessionMap.remove(exist.getSession().getId());
            		list.remove(exist);
                    cacheMap.remove(exist.getUser().getUsername());
                    usernames.remove(exist.getUser().getUsername());
            	}                              
            } 
    }
    
    public static Map<String, SocketUser> getSessionMap(){
    	return sessionMap;
    }
    
    public static List<SocketUser> getSocketUser(){
    	return list;
    }
    
    /**
     * 根据用户id获取缓存信息
     * @param userId 用户id
     * @return
     */
    public static SocketUser getSocketUserByUserId(String userId) {
        return cacheMap.get(userId);
    }

    /**
     * 根据sessonId获取缓存信息
     * @param sessionId
     * @return
     */
    public static SocketUser getSocketUserBySeesionId(String sessionId) {
        return sessionMap.get(sessionId);
    }

    /**
     * 获取在线人数
     * @return
     */
    public static long getOnlineNum() {
        return list.stream().
                filter(us->us.getUser().getState() == UserStatus.Hide||us.getUser().getState() == UserStatus.Online).count();
    }

    /**
     * 获取缓存数量
     * @return
     */
    public static int getCashNum() {
        return cacheMap.keySet().size();
    }

    /**
     * 获取在线用户名列表
     * @return
     */
    public static Set<String> getUsernames() {
        return usernames;
    }


    /**
     * 清除离线时间超过{timeoutHour}小时的缓存
     * @param timeoutHour
     */
    public static void cleanCashData(int timeoutHour){
    	if(timeoutHour > 0){
    		long now = new Date().getTime();
    		List<SocketUser> removeCash = list.stream().filter((sc)->{
    			if(!sc.getSession().isOpen()){
    				Date date = sc.getUser().getLeaveTime();
    				if(date == null){
    					return true; // 问题数据直接删
    				}else{
    					long diff= now - date.getTime();
    					int hour = (int) (diff/(60*60*1000));
    					if(hour > timeoutHour){
    						return true;
    					}
    				}
    			}
    			return false;
    		}).collect(Collectors.toList());
    		if(removeCash.size() > 0){
    			removeCash.stream().forEach((sc)->{
    				list.remove(sc);
                    cacheMap.remove(sc.getUser().getUsername());
    				sessionMap.remove(sc.getSession().getId());
                    usernames.remove(sc.getUser().getUsername());
    			});
    			removeCash = null;
    			System.gc();
    		}
    	}
    }
}
